<?php

namespace App\Http\Common\curl;

use Illuminate\Support\Facades\Log;

class CurlUtil
{
    /**
     * exec curl get
     * @param string $url
     * @param array $params
     * @param array $header
     * @param int $retries 错误重试次数
     * @return bool|mixed
     */
    public static function xget($url, array $params = [], array $header = [], $retries = 3)
    {
        $header[] = 'X-CHAIN-UUID: ' . CHAIN_UUID;
        $fullUrl = self::buildGetUrl($url, $params);
        Log::info('LogCode::CURL_GET_REQUEST', array(
            'url' => $url,
            'fullUrl' => $fullUrl,
            'params' => $params,
            'retries' => $retries,
        ));

        $defaults = array(
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'GET',
            CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_HTTPHEADER => $header,
            CURLOPT_CONNECTTIMEOUT => 10,          // timeout on connect
            CURLOPT_TIMEOUT => 10,                 // timeout on response
        );

        $resp = self::exec($fullUrl, $defaults, $retries);

        Log::info('LogCode::CURL_GET_RESPONSE', array(
            'response' => $resp,
        ));

        return $resp;
    }

    /**
     * exec curl post
     * @param string $url
     * @param string $body [CURLOPT_POSTFIELDS (urlencoded string)]
     * @param array $header
     * @param int $retries 错误重试次数
     * @param array $specificConfig 特定配置，可配置CURLOPT支持的选项
     * @return bool|mixed
     */
    public static function xpost($url, $body = '', array $header = [], $retries = 3, $specificConfig = [])
    {
        $header[] = 'X-CHAIN-UUID: ' . CHAIN_UUID;
        Log::info('LogCode::CURL_POST_REQUEST', array(
            'url' => $url,
            'body' => $body,
            'header' => $header,
            'retries' => $retries,
        ));

        $defaults = array(
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_FOLLOWLOCATION => 1,
            CURLOPT_HTTPHEADER => $header,
            CURLOPT_POSTFIELDS => $body,
            CURLOPT_CONNECTTIMEOUT => 10,          // timeout on connect
            CURLOPT_TIMEOUT => 10,                 // timeout on response
        );

        if ($specificConfig) {
            $defaults = $specificConfig + $defaults;
        }

        $resp = self::exec($url, $defaults, $retries);

        Log::info('LogCode::CURL_POST_RESPONSE', array(
            'response' => $resp,
        ));

        return $resp;
    }

    /**
     * @param string $url
     * @param array $opt curl options
     * @param $retries
     * @return bool|mixed
     */
    private static function exec($url, array $opt, $retries)
    {
        try {
            $ch = curl_init($url);
            curl_setopt_array($ch, $opt);
            $result = false;
            while (($result === false) && (--$retries > 0)) {
                $start = microtime(true);
                $result = curl_exec($ch);
                $time = number_format(microtime(true) - $start, 5, '.', '');
                Log::info('LogCode::CURL_EXEC_TIME', array(
                    'exec_time' => $time,
                ));
            }

            $httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if ($httpStatus != 200) {
                if ($httpStatus == 0) {
                    $errno = curl_errno($ch);
                    $error = curl_error($ch);
                } else {
                    $errno = $httpStatus;
                    $error = $result;
                }

                Log::warning('LogCode::CURL_EXEC_HTTP_CODE_NOT_OK', compact('error', 'errno'));
            }

            curl_close($ch);

            return $result;
        } catch (\Exception $e) {
            Log::warning('LogCode::CURL_EXEC_ERROR', [$e]);

            return false;
        }
    }

    /**
     * 构建GET请求URL
     * 如：url = http://xxx.com/a.php?a=a&b=b getParams = ['c' => 'c']
     * 输出：http://xxx.com/a.php?a=a&b=b&c=c
     * @param $url
     * @param array $getParams
     * @return string
     */
    private static function buildGetUrl($url, array $getParams): string
    {
        // 分离baseUrl与查询字串
        @list($baseUrl, $queryStr) = explode('?', $url);
        $getParams = http_build_query($getParams);

        if (empty($getParams) && empty($queryStr)) {
            return $baseUrl;
        } elseif (empty($getParams)) {
            return "{$baseUrl}?{$queryStr}";
        } elseif (empty($queryStr)) {
            return "{$baseUrl}?{$getParams}";
        } else {
            return "{$baseUrl}?{$queryStr}&{$getParams}";
        }

    }
}
